﻿namespace System.ServiceModel.DomainServices.Client
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Linq;

    public sealed class SubmitOperation : OperationBase
    {
        private Action<SubmitOperation> _cancelAction;
        private EntityChangeSet _changeSet;
        private Action<SubmitOperation> _completeAction;

        internal SubmitOperation(EntityChangeSet changeSet, Action<SubmitOperation> completeAction, object userState, Action<SubmitOperation> cancelAction) : base(userState)
        {
            if (changeSet == null)
            {
                throw new ArgumentNullException("changeSet");
            }
            this._cancelAction = cancelAction;
            this._completeAction = completeAction;
            this._changeSet = changeSet;
        }

        protected override void CancelCore()
        {
            this._cancelAction(this);
        }

        internal void Complete()
        {
            base.Complete(null);
        }

        internal void Complete(Exception error)
        {
            if (typeof(DomainException).IsAssignableFrom(error.GetType()))
            {
                base.Complete(error);
            }
            else
            {
                string message = string.Format(CultureInfo.CurrentCulture, Resource.DomainContext_SubmitOperationFailed, new object[] { error.Message });
                DomainOperationException exception = error as DomainOperationException;
                if (exception != null)
                {
                    error = new DomainOperationException(message, exception);
                }
                else
                {
                    error = new DomainOperationException(message, error);
                }
                base.Complete(error);
            }
        }

        internal void Complete(OperationErrorStatus errorStatus)
        {
            DomainOperationException exception = null;
            if (errorStatus == OperationErrorStatus.ValidationFailed)
            {
                exception = new DomainOperationException(Resource.DomainContext_SubmitOperationFailed_Validation, OperationErrorStatus.ValidationFailed);
            }
            else if (errorStatus == OperationErrorStatus.Conflicts)
            {
                exception = new DomainOperationException(Resource.DomainContext_SubmitOperationFailed_Conflicts, OperationErrorStatus.Conflicts);
            }
            base.Complete((Exception) exception);
        }

        protected override void InvokeCompleteAction()
        {
            if (this._completeAction != null)
            {
                this._completeAction(this);
            }
        }

        public EntityChangeSet ChangeSet
        {
            get
            {
                return this._changeSet;
            }
        }

        public IEnumerable<Entity> EntitiesInError
        {
            get
            {
                return Enumerable.Where<Entity>(this._changeSet, delegate (Entity p) {
                    if (p.EntityConflict == null)
                    {
                        return p.HasValidationErrors;
                    }
                    return true;
                });
            }
        }

        protected override bool SupportsCancellation
        {
            get
            {
                return (this._cancelAction != null);
            }
        }
    }
}

